Common Lisp defines three macros,
define-modify-macro, defsetf, and
define-setf-method, that allow the user to extend
generalized variables in various ways.
This macro defines a “read-modify-write” macro similar to
incfanddecf. The macro name is defined to take a place argument followed by additional arguments described by arglist. The call(name place args...)will be expanded to
(callf func place args...)which in turn is roughly equivalent to
(setf place (func place args...))For example:
(define-modify-macro incf (&optional (n 1)) +) (define-modify-macro concatf (&rest args) concat)Note that
&keyis not allowed in arglist, but&restis sufficient to pass keywords on to the function.Most of the modify macros defined by Common Lisp do not exactly follow the pattern of
define-modify-macro. For example,pushtakes its arguments in the wrong order, andpopis completely irregular. You can define these macros “by hand” usingget-setf-method, or consult the source file cl-macs.el to see how to use the internalsetfbuilding blocks.
This is the simpler of two
defsetfforms. Where access-fn is the name of a function which accesses a place, this declares update-fn to be the corresponding store function. From now on,(setf (access-fn arg1 arg2 arg3) value)will be expanded to
(update-fn arg1 arg2 arg3 value)The update-fn is required to be either a true function, or a macro which evaluates its arguments in a function-like way. Also, the update-fn is expected to return value as its result. Otherwise, the above expansion would not obey the rules for the way
setfis supposed to behave.As a special (non-Common-Lisp) extension, a third argument of
ttodefsetfsays that theupdate-fn's return value is not suitable, so that the abovesetfshould be expanded to something more like(let ((temp value)) (update-fn arg1 arg2 arg3 temp) temp)Some examples of the use of
defsetf, drawn from the standard suite of setf methods, are:(defsetf car setcar) (defsetf symbol-value set) (defsetf buffer-name rename-buffer t)
This is the second, more complex, form of
defsetf. It is rather likedefmacroexcept for the additional store-var argument. The forms should return a Lisp form which stores the value of store-var into the generalized variable formed by a call to access-fn with arguments described by arglist. The forms may begin with a string which documents thesetfmethod (analogous to the doc string that appears at the front of a function).For example, the simple form of
defsetfis shorthand for(defsetf access-fn (&rest args) (store) (append '(update-fn) args (list store)))The Lisp form that is returned can access the arguments from arglist and store-var in an unrestricted fashion; macros like
setfandincfwhich invoke this setf-method will insert temporary variables as needed to make sure the apparent order of evaluation is preserved.Another example drawn from the standard package:
(defsetf nth (n x) (store) (list 'setcar (list 'nthcdr n x) store))
This is the most general way to create new place forms. When a
setfto access-fn with arguments described by arglist is expanded, the forms are evaluated and must return a list of five items:
- A list of temporary variables.
- A list of value forms corresponding to the temporary variables above. The temporary variables will be bound to these value forms as the first step of any operation on the generalized variable.
- A list of exactly one store variable (generally obtained from a call to
gensym).- A Lisp form which stores the contents of the store variable into the generalized variable, assuming the temporaries have been bound as described above.
- A Lisp form which accesses the contents of the generalized variable, assuming the temporaries have been bound.
This is exactly like the Common Lisp macro of the same name, except that the method returns a list of five values rather than the five values themselves, since Emacs Lisp does not support Common Lisp's notion of multiple return values.
Once again, the forms may begin with a documentation string.
A setf-method should be maximally conservative with regard to temporary variables. In the setf-methods generated by
defsetf, the second return value is simply the list of arguments in the place form, and the first return value is a list of a corresponding number of temporary variables generated bygensym. Macros likesetfandincfwhich use this setf-method will optimize away most temporaries that turn out to be unnecessary, so there is little reason for the setf-method itself to optimize.
This function returns the setf-method for place, by invoking the definition previously recorded by
defsetfordefine-setf-method. The result is a list of five values as described above. You can use this function to build your ownincf-like modify macros. (Actually, it is better to use the internal functionscl-setf-do-modifyandcl-setf-do-store, which are a bit easier to use and which also do a number of optimizations; consult the source code for theincffunction for a simple example.)The argument env specifies the “environment” to be passed on to
macroexpandifget-setf-methodshould need to expand a macro in place. It should come from an&environmentargument to the macro or setf-method that calledget-setf-method.See also the source code for the setf-methods for
applyandsubstring, each of which works by callingget-setf-methodon a simpler case, then massaging the result in various ways.
Modern Common Lisp defines a second, independent way to
specify the setf behavior of a function, namely
“setf functions” whose names are lists
(setf name) rather than
symbols. For example, (defun (setf foo) ...) defines
the function that is used when setf is applied to
foo. This package does not currently support
setf functions. In particular, it is a compile-time
error to use setf on a form which has not already
been defsetf'd or otherwise declared; in newer
Common Lisps, this would not be an error since the function
(setf func) might be defined
later.